Enumerable = {}

setmetatable(Enumerable, {__call = function (self,...) return self:New(...) end})

function Enumerable:New(list)
    print("Enumerable.New()")
    local self = setmetatable({}, {__index = Enumerable})
    self.list = list
    self.index = nil
    self.iterator = function ()
        local v
        self.index, v = next(self.list, self.index)
        return self.index, v
    end

    return self
end

function Enumerable.From(list)
    print("Enumerable.From()")
    if type(list) ~= "table" then
        error("Enumerable.From(list)===>> list is not table")
    end
    
    local enum = Enumerable(list)

    return enum
end

function Enumerable:Foreach(func)
    print("Enumerable.Foreach()")
    local k, v = self.iterator()
    while k do
        func(v)
        k, v = self.iterator()
    end
end

function Enumerable:ToList()
    local list = {}
    local k, v = self.iterator()
    while k do
        table.insert(list, v)
        k, v = self.iterator()
    end
    return list
end

function Enumerable:OrderBy(selector)
    -- local list = self:ToList()
    -- table.sort(list, comparer)
    -- return list
end

function Enumerable:OrderByDesc(selector)

end

function Enumerable:Select(predicate)
    print("Enumerable.Select()")
    local fun = self.iterator
    self.iterator = function()
        local i, v 
        i, v  = fun()
        if i then
            return i, predicate(v)
        else
            return i
        end
    end
    return self
end

function Enumerable:Where(predicate)
    print("Enumerable.Where()")
    local fun = self.iterator
    self.iterator = function ()
        local i, v 
        repeat
            i, v = fun()
        until i == nil or predicate(v)

        return i, v
    end
    return self
end

function Enumerable:Iterator()
    return self.iterator
end

return Enumerable